Async + RAML Data Types in AMF
This is a technical document, this information is intended for experienced users
Within the Async specification it is possible to use RAML data types to define a payload, taking into account that the schema format is specified accordingly. Both specifications have their own distinct referencing and modularization mechanisms, and it is not clear where to draw the line to determine where one specification stops, and the other one starts. This document will describe how to use RAML types in Async when using AMF.
Referencing external RAML content using $ref
In order to support referencing RAML content in external files, AMF allows the use of the $ref
mechanism present in Async.
This enables referencing data type fragments, data types present in libraries, as well as any RAML content present in yaml or json files.
However, the usage of $ref
in this scenario has some restrictions. Given that the payload content must comply with RAML,
the $ref
may only be used at the root of the payload definition as an exception to the RAML specification.
Its target content must be valid structurally according to the relevant RAML specification:
schemaFormat: application/RAML+yaml;version=1.0
payload:
$ref: “...” # must reference raml content
schemaFormat: application/raml+yaml;version=1.0
payload:
type: object
properties:
user:
$ref: “...” # '$ref' is not valid in RAML
The following section shows all supported use cases when using this referencing mechanism, adding additional comments if necessary.
Reference to data type fragments
The data type fragment must be self-contained, meaning it cannot depend on any definition made in the root API. The following example is valid for this use case.
schemaFormat: application/raml+yaml;version=1.0
payload:
$ref: external-data-type.raml
#%RAML 1.0 DataType
type: object
properties:
a: string | object
The following referenced data type is invalid as it is not self-contained, meaning the data type fragment depends on type definitions which will not be resolved in the root API.
Due to known limitations this API will not return any validations (error or warning), but the reference to the type Other
inside the data type will not be made, leaving it unresolved.
components:
schemas:
Other: ...
channels:
users/signup:
subscribe:
message:
schemaFormat: application/raml+yaml;version=1.0
payload:
$ref: external-data-type.raml
#%RAML 1.0 DataType
type: object
properties:
a: Other
Use of relative pointers to nested content within the data type fragment is not supported, like in the following invalid example:
schemaFormat: application/raml+yaml;version=1.0
payload:
$ref: external-data-type.raml#/properties/a
Reference to types in library fragments
For the case of libraries, type definitions can be referenced using the following fixed pointer: {lib}#/types/{typeName}
.
When referencing types defined in a library, the included content will have context of other type definitions present in the original library.
This can be seen in the following valid example where the type User references another type present in the external library.
schemaFormat: application/raml+yaml;version=1.0
payload:
$ref: ../external-library.raml#/types/User
#%RAML 1.0 Library
types:
User:
type: Other | string
Other:
type: string
The external library must be self-contained, meaning it cannot depend on types defined in the root API. In the following invalid example, the library depends on the definition of the type Other, which will not be resolved from the definitions present in the main API.
components:
schemas:
Other: ...
channels:
users/signup:
subscribe:
message:
schemaFormat: application/raml+yaml;version=1.0
payload:
$ref: ../external-library.raml#/types/User
#%RAML 1.0 Library
types:
User:
type: Other | string
Reference to external yaml/json files
When referencing external yaml or json files, the $ref
inlines the content.
Relative json pointers can be used to reference content that is nested within the file, but taking into account the following limitation:
the external file must not be a known RAML fragment or API specification.
The following case is a valid reference making use of relative json pointers.
schemaFormat: application/raml+yaml;version=1.0
payload:
$ref: external-yaml.yaml#/definitions/User
definitions:
User:
type: string | object
As previously mentioned, when the target file is a known RAML fragment or API specification free use of relative json pointers is not supported. The following example shows an invalid example when using relative json pointer to reference an external RAML specification:
schemaFormat: application/raml+yaml;version=1.0
payload:
$ref: ../api.raml#/types/User
#%RAML 1.0
title: Instagram API
types:
User:
type: object
Inlined RAML types
The simplest way to define a RAML type in Async is by defining your content inlined under the payload
facet while using the appropriate schema format like so:
schemaFormat: application/raml+yaml;version=1.0
payload: # The following is a RAML data type
type: object
properties:
a: object | string
additionalProperties: false
All content within the payload will be considered strictly RAML, except when using ‘$ref’ at the root of the payload (see the previous section for more details).
Isolated RAML context
When defining inlined types, its context is fully restricted from the content defined outside the payload facet.
This means that any reference to content defined in the components
facet of the main Async API will not be resolved.
components:
schemas:
User: ...
channels:
users/signup:
subscribe:
message:
schemaFormat: application/raml+yaml;version=1.0
payload:
type: User #unresolved reference
Limited RAML referencing mechanism
RAML has its own referencing mechanism to include content from external files using a reserved yaml tag !include
.
AMF will only support referencing external data type fragments using the !include
tag.
Furthermore, this will only work in Async APIs defined in yaml format, as json has no way of defining tags.
As this syntax is valid within a RAML context, including data types fragments can be made at the root of the payload content, or nested within other inlined content:
schemaFormat: application/raml+yaml;version=1.0
payload: !include external-data-type.raml
schemaFormat: application/raml+yaml;version=1.0
payload:
type: object
properties:
id: string
user: !include external-data-type.raml